from graph import prim_mst, build_mst_graph, preorder_traversal
from params import priorities, max_orders_per_uav, max_mileage_per_uav, speed_uav
from utils import time_now


class Path:
    def __init__(self, dc_id, orders_list: list, distance_matrix):
        self.dc_id = dc_id
        self.orders_list = orders_list[:]
        self.__min_mileage = -1
        self.__ups_lists = {}

        for order in orders_list:
            if order.belongs_to in self.__ups_lists.keys():
                self.__ups_lists[order.belongs_to] += 1
            else:
                self.__ups_lists[order.belongs_to] = 1

        self.__traversal_order = None
        self.__calculate_min_mileage(distance_matrix)

    @property
    def expire_time(self):
        res = 48 * 60
        for order in self.orders_list:
            if order.expire_time < res:
                res = order.expire_time
        return res

    @property
    def need_be_distributed(self):
        """在所有订单中，如果某一订单过期时间还剩无人机最大飞行时间时，需要配送"""
        return self.expire_time <= time_now() + (max_mileage_per_uav // speed_uav)

    @property
    def orders_num(self):
        return len(self.orders_list)

    def __calculate_min_mileage(self, distance_matrix):
        ups_graph = {self.dc_id: []}
        for site2 in self.__ups_lists.keys():
            tmp = [site2, distance_matrix[self.dc_id][site2]]
            ups_graph[self.dc_id].append(tmp)
        for site in self.__ups_lists.keys():
            ups_graph[site] = []
            for site2 in self.__ups_lists.keys():
                if site != site2:
                    ups_graph[site].append([site2, distance_matrix[site][site2]])
            ups_graph[site].append([self.dc_id, distance_matrix[site][self.dc_id]])
        mst_edges = prim_mst(ups_graph)
        # 构建最小生成树图
        mst_graph = build_mst_graph(mst_edges)

        # 对最小生成树进行先序遍历
        self.__traversal_order = preorder_traversal(mst_graph, self.dc_id)
        # print("先序遍历的顶点顺序:", self.__traversal_order)

        # 计算遍历路径权重和
        self.__min_mileage = 0
        p_start = self.dc_id
        for p_end in self.__traversal_order[::-1]:
            self.__min_mileage += distance_matrix[p_start][p_end]
            p_start = p_end

    @property
    def traverse_order(self):
        res = self.__traversal_order[:]
        res.append(self.dc_id)
        return res

    @property
    def min_mileage(self):
        return self.__min_mileage

    def merge(self, path, distance_matrix):
        if path.orders_num + self.orders_num <= max_orders_per_uav:
            new_orders_list = self.orders_list[:]
            new_orders_list.extend(path.orders_list)

            new_path = Path(self.dc_id, new_orders_list, distance_matrix)

            if new_path.min_mileage > max_mileage_per_uav:
                return None

            return new_path

        return None
